/*-------------------------------------------------------------------------
   io.h - handle io on the EC

   Copyright (C) 2010 One Laptop per Child

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   In other words, you are welcome to use, share and improve this program.
   You are forbidden to forbid anyone else to use, share and improve
   what you give them.   Help stamp out software-hoarding!

   As a special exception, you may use this file as part of a free software
   library for the XO of the One Laptop per Child project without restriction.
   Specifically, if other files instantiate
   templates or use macros or inline functions from this file, or you compile
   this file and link it with other files to produce an executable, this
   file does not by itself cause the resulting executable to be covered by
   the GNU General Public License.  This exception does not however
   invalidate any other reasons why the executable file might be covered by
   the GNU General Public License.
-------------------------------------------------------------------------*/

#ifndef IO_H
#define IO_H

#include "chip.h"

/* portbit mappings for all of the IO lines
 * bit lower nibble (bits 2-0, bit 3 unused)
 * port is uppper nibble (bits 7-4)
*/

// Port 0 GPIO 00-07
#define GPIO_PORT_0	0x00
#define GPIO_00		0x00
#define GPIO_01		0x01
#define GPIO_02		0x02
#define GPIO_03		0x03
#define GPIO_04		0x04
#define GPIO_05		0x05
#define GPIO_06		0x06
#define GPIO_07		0x07

// Port 1 GPIO 08 - 0F
#define GPIO_PORT_1 0x01
#define GPIO_08		0x10
#define GPIO_09		0x11
#define GPIO_0A		0x12
#define GPIO_0B		0x13
#define GPIO_0C		0x14
#define GPIO_0D		0x15
#define GPIO_0E		0x16
#define GPIO_0F		0x17

// Port 2 GPIO 10 - 17
#define GPIO_PORT_2	0x02
#define GPIO_10		0x20
#define GPIO_11		0x21
#define GPIO_12		0x22
#define GPIO_13		0x23
#define GPIO_14		0x24
#define GPIO_15		0x25
#define GPIO_16		0x26
#define GPIO_17		0x27

// Port 3 GPIO 18 - 1F
#define GPIO_PORT_3	0x03
#define GPIO_18		0x30
#define GPIO_19		0x31
#define GPIO_1A		0x32
#define GPIO_1B		0x33
#define GPIO_1C		0x34
#define GPIO_1D		0x35
#define GPIO_1E		0x36
#define GPIO_1F		0x37

// Port 4 GPIO 20 - 07
#define GPIO_PORT_4	0x04
#define GPIO_20		0x40
#define GPIO_21		0x41
#define GPIO_22		0x42
#define GPIO_23		0x43
#define GPIO_24		0x44
#define GPIO_25		0x45
#define GPIO_26		0x46
#define GPIO_27		0x47

// Port 5 GPIO 28 - 2F
#define GPIO_PORT_5	0x05
#define GPIO_28		0x50
#define GPIO_29		0x51
#define GPIO_2A		0x52
#define GPIO_2B		0x53
#define GPIO_2C		0x54
#define GPIO_2D		0x55
#define GPIO_2E		0x56
#define GPIO_2F		0x57

// Port 6 GPIO 30 - 07
#define GPIO_PORT_6	0x06
#define GPIO_30		0x60
#define GPIO_31		0x61
#define GPIO_32		0x62
#define GPIO_33		0x63
#define GPIO_34		0x64
#define GPIO_35		0x65
#define GPIO_36		0x66
#define GPIO_37		0x67

// Port 7 GPIO 3c - 3f
#define GPIO_PORT_7	0x07
#define GPIO_38		0x70
#define GPIO_39		0x71
#define GPIO_3A		0x72
#define GPIO_3B		0x73
#define GPIO_3C		0x74
#define GPIO_3D		0x75
#define GPIO_3E		0x76
#define GPIO_3F		0x77

// Port 8 GPIO 40 - 47
#define GPIO_PORT_8	0x08
#define GPIO_40		0x80
#define GPIO_41		0x81
#define GPIO_42		0x82
#define GPIO_43		0x83
#define GPIO_44		0x84
#define GPIO_45		0x85
#define GPIO_46		0x86
#define GPIO_47		0x87

// Port 9 GPIO 48 - 4f
#define GPIO_PORT_9	0x09
#define GPIO_48		0x90
#define GPIO_49		0x91
#define GPIO_4A		0x92
#define GPIO_4B		0x93
#define GPIO_4C		0x94
#define GPIO_4D		0x95
#define GPIO_4E		0x96
#define GPIO_4F		0x97

// Port a GPIO 50 - 57
#define GPIO_PORT_a	0x0a
#define GPIO_50		0xa0
#define GPIO_51		0xa1
#define GPIO_52		0xa2
#define GPIO_53		0xa3
#define GPIO_54		0xa4
#define GPIO_55		0xa5
#define GPIO_56		0xa6
#define GPIO_57		0xa7

// Port b GPIO 58 - 59
#define GPIO_PORT_b	0x0b
#define GPIO_58		0xb0
#define GPIO_59		0xb1
//#define GPIO_5a		0x92
//#define GPIO_5b		0x93
//#define GPIO_5c		0x94
//#define GPIO_5d		0x95
//#define GPIO_5e		0x96
//#define GPIO_5f		0x97

// Port c GPXIOA 00 - 07
#define GPIO_PORT_c	0x0c
#define GPXIOA_00	0xc0
#define GPXIOA_01	0xc1
#define GPXIOA_02	0xc2
#define GPXIOA_03	0xc3
#define GPXIOA_04	0xc4
#define GPXIOA_05	0xc5
#define GPXIOA_06	0xc6
#define GPXIOA_07	0xc7

// Port d GPXIOA 08 - 0f
#define GPIO_PORT_d	0x0d
#define GPXIOA_08	0xd0
#define GPXIOA_09	0xd1
#define GPXIOA_0A	0xd2
#define GPXIOA_0B	0xd3
#define GPXIOA_0C	0xd4
#define GPXIOA_0D	0xd5
#define GPXIOA_0E	0xd6
#define GPXIOA_0F	0xd7

// Port E is reserved on the KB3930

// Port f GPXIOD 08 - 0f
#define GPIO_PORT_f	0x0f
#define GPXIOD_00	0xf0
#define GPXIOD_01	0xf1
#define GPXIOD_02	0xf2
#define GPXIOD_03	0xf3
#define GPXIOD_04	0xf4
#define GPXIOD_05	0xf5
#define GPXIOD_06	0xf6
#define GPXIOD_07	0xf7

/* since the arguments to these macros are constants, all of the
 * math will disappear.
 */
#define setbit(x)     (1 << (x))
#define clearbit(x) (~(1 << (x)))

#define IO_OUTPUT_HIGH(portbit) \
    do { \
        gpio[GPIOD00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_OUTPUT_LOW(portbit) \
    do { \
        gpio[GPIOD00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)

#define IO_ACTIVE_HIGH(portbit) \
    (!!(gpio[GPIOIN00 + ((portbit) >> 4)] & setbit((portbit) & 7)))

#define IO_ACTIVE_LOW(portbit) \
    (!(gpio[GPIOIN00 + ((portbit) >> 4)] & setbit((portbit) & 7)))

#define IO_INPUT_ONLY(portbit) \
    do { \
            gpio[GPIOOE00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
            gpio[GPIOIE00 + ((portbit) >> 4)] |= setbit((portbit) & 7);   \
} while (0)

#define IO_OUTPUT_ONLY(portbit) \
    do { \
            gpio[GPIOIE00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
            gpio[GPIOOE00 + ((portbit) >> 4)] |= setbit((portbit) & 7);   \
} while (0)

#define IO_INPUT_ENABLE(portbit) \
    do { \
            gpio[GPIOIE00 + ((portbit) >> 4)] |= setbit((portbit) & 7);   \
} while (0)

#define IO_INPUT_DISABLE(portbit) \
    do { \
            gpio[GPIOIE00 + ((portbit) >> 4)] &= clearbit((portbit) & 7);  \
} while (0)

#define IO_OUTPUT_ENABLE(portbit) \
    do { \
            gpio[GPIOOE00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_OUTPUT_DISABLE(portbit) \
    do { \
            gpio[GPIOOE00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)

#define IO_ALT_OUT_ENABLE(portbit) \
        do { \
            gpio[GPIOFS00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_ALT_OUT_DISABLE(portbit) \
        do { \
            gpio[GPIOFS00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)

#define IO_PORT_LOW(port,mask) \
        do { \
            gpio[GPIOD00 + port] &= ~mask; \
} while(0)

#define IO_OPEN_DRAIN_ENABLE(portbit) \
    do { \
            gpio[GPIOOD00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_PORT_HIGH(port,mask) \
    do { \
            gpio[GPIOD00 + port] |= mask; \
} while(0)

#define IO_PORT_READ(port,mask) \
        (gpio[GPIOIN00 + port] & mask)

#define IO_PORT_READ_BIT(portbit) \
        (IO_PORT_READ(((portbit) >> 4), setbit( (portbit) & 7) ))

#define IO_PORT_SET(port,value) \
    do { \
            gpio[GPIOD00 + port] = value; \
} while(0)

#define IO_PULLUP_ENABLE(portbit) \
    do { \
            gpio[GPIOPU00 + ((portbit) >> 4)] |= setbit((portbit) & 7);   \
} while (0)

#define IO_PULLUP_DISABLE(portbit) \
    do { \
            gpio[GPIOPU00 + ((portbit) >> 4)] &= clearbit((portbit) & 7);  \
} while (0)

#define IO_WAKEUP_ENABLE(portbit) \
    do { \
            gpwu[GPWUEN00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_DISABLE(portbit) \
    do { \
            gpwu[GPWUEN00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_PENDING(portbit) \
    (gpwu[GPWUPF00 + ((portbit) >> 4)] & setbit((portbit) & 7))

#define IO_WAKEUP_PENDING_CLEAR(portbit) \
    do { \
            gpwu[GPWUPF00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_POLARITY_HIGH(portbit) \
    do { \
            gpwu[GPWUPS00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_POLARITY_LOW(portbit) \
    do { \
            gpwu[GPWUPS00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_LEVEL(portbit) \
    do { \
            gpwu[GPWUEL00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_EDGE(portbit) \
    do { \
            gpwu[GPWUEL00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_TOGGLE_ENABLE(portbit) \
    do { \
            gpwu[GPWUCHG00 + ((portbit) >> 4)] |= setbit((portbit) & 7); \
} while (0)

#define IO_WAKEUP_TOGGLE_DISABLE(portbit) \
    do { \
            gpwu[GPWUCHG00 + ((portbit) >> 4)] &= clearbit((portbit) & 7); \
} while (0)


void set_pwm(unsigned char channel,unsigned int value);
void set_LED_PWR		(unsigned int value);
void set_LED_CHG_RED	(unsigned int value);
void set_LED_CHG_GREEN	(unsigned int value);

#define PWM_8_BIT_MAX	255
#define PWM_12_BIT_MAX	4095
#define PWM_14_BIT_MAX	16383

unsigned int read_pwm(unsigned char channel);

#define DEBUG_E3_LOW
//IO_OUTPUT_LOW(GPIO_E3) FIXME:
#define DEBUG_E3_HIGH
//IO_OUTPUT_HIGH(GPIO_E3) FIXME:

extern unsigned char data board_rev;
#define BOARD_GENERATION   0x01   // XO-1.75

unsigned char read_VIN_OK(void);
unsigned char read_MAIN_ON(void);
unsigned char read_SUSC(void);
unsigned char read_CHG(void);
unsigned char read_PCI_RST(void);
unsigned char read_EC_SPI_CMD(void);
unsigned char read_EC_SPI_ACK(void);

// Output
void enable_CHG(void);
void disable_CHG(void);
void enable_CC0(void);
void disable_CC0(void);
void enable_CV_SET(void);
void disable_CV_SET(void);
void enable_VR_ON(void);
void disable_VR_ON(void);
void enable_PWR_BUT_OUT(void);
void disable_PWR_BUT_OUT(void);
void enable_TRICKLE_CHG(void);
void disable_TRICKLE_CHG(void);
void enable_KBD_PWREN(void);
void disable_KBD_PWREN(void);
void enable_TCM_CLK(void);
void disable_TCM_CLK(void);
void enable_DCON_EN(void);
void disable_DCON_EN(void);
void enable_RSM_RST(void);
void disable_RSM_RST(void);
void enable_TCM_DAT(void);
void disable_TCM_DAT(void);
void enable_PWR_GOOD(void);
void disable_PWR_GOOD(void);
void enable_MSD_PWROFF(void);
void disable_MSD_PWROFF(void);
void set_KEY_OUT(unsigned char mask);
void clr_KEY_OUT(unsigned char mask);
void makeport_KEY_OUT(unsigned char value);

void output_enable_PCIRST(void);
void output_disable_PCIRST(void);
void config_all_PS2_as_PS2(void);
void config_all_PS2_as_gpio(void);

void ClearEventPendingFlags(void);

unsigned int get_matrix_keys(void);
void get_board_id(void);
void init_board_rev(void);
void init_default_io(void);
void uart_io_init(void);
void ps2_io_init(void);

#define SD_SLOT2_PWROFF {if(PlatformID>0xd1) enable_MSD_PWROFF() ;}
#define SD_SLOT2_PWRON  {if(PlatformID>0xd1) disable_MSD_PWROFF();}

#if ! USE_MACROS_FOR_IO
unsigned char read_CHRG_AC_OK(void);
void enable_EN_MAIN_PWR(void);
void disable_EN_MAIN_PWR(void);
void output_enable_EN_MAIN_PWR(void);

void enable_EN_VCORE_PWR(void);
void disable_EN_VCORE_PWR(void);
void output_enable_EN_VCORE_PWR(void);

void enable_EN_1_8V_PMIC(void);
void disable_EN_1_8V_PMIC(void);
void output_enable_EN_1_8V_PMIC(void);

void enable_EN_1_8V_GPIO(void);
void disable_EN_1_8V_GPIO(void);
void output_enable_EN_1_8V_GPIO(void);

void enable_EN_3_3V_SOC(void);
void disable_EN_3_3V_SOC(void);
void output_enable_EN_3_3V_SOC(void);

void enable_EN_3_3V_NAND(void);
void disable_EN_3_3V_NAND(void);
void output_enable_EN_3_3V_NAND(void);

void enable_EN_DCON_PWR(void);
void disable_EN_DCON_PWR(void);
void output_enable_EN_DCON_PWR(void);

void enable_EN_1_5V_DDR3(void);
void disable_EN_1_5V_DDR3(void);
void output_enable_EN_1_5V_DDR3(void);

void enable_EN_1_2V(void);
void disable_EN_1_2V(void);
void output_enable_EN_1_2V(void);

void enable_SOC_RESET(void);
void disable_SOC_RESET(void);
void output_enable_SOC_RESET(void);

void enable_EN_USB_PWR(void);
void disable_EN_USB_PWR(void);
void output_enable_EN_USB_PWR(void);

void enable_CHRG_TRICKLE(void);
void disable_CHRG_TRICKLE(void);
void output_enable_CHRG_TRICKLE(void);

void enable_CHRG_DQ(void);
void disable_CHRG_DQ(void);
void output_enable_CHRG_DQ(void);
void output_disable_CHRG_DQ(void);

void enable_CHRG_VOL_SEL(void);
void disable_CHRG_VOL_SEL(void);
void output_enable_CHRG_VOL_SEL(void);

void enable_EN_SD1_PWR(void);
void disable_EN_SD1_PWR(void);
void output_enable_EN_SD1_PWR(void);

void enable_EN_SD2_PWR(void);
void disable_EN_SD2_PWR(void);
void output_enable_EN_SD2_PWR(void);

void input_enable_PWR_BUT(void);
void input_enable_ALL_PWRGOOD(void);
void input_enable_SYS_RESET(void);
void input_enable_CHRG_AC_OK(void);
void input_enable_RESTORE(void);
void input_enable_PWR_LMT_ON(void);

unsigned char read_PWR_BTN(void);
unsigned char read_ALL_PWRGOOD(void);
unsigned char read_SYS_RESET(void);
unsigned char read_RESTORE(void);
unsigned char read_PWR_LMT_ON(void);

void set_LED_PWR_on     (void);
void set_LED_PWR_off    (void);
void output_enable_LED_PWR(void);
void output_disable_LED_PWR(void);

void set_LED_CHG_RED_on	(void);
void set_LED_CHG_RED_off(void);
void output_enable_LED_CHG_RED(void);
void output_disable_LED_CHG_RED(void);

void set_LED_CHG_GREEN_on (void);
void set_LED_CHG_GREEN_off(void);
void output_enable_LED_CHG_GREEN(void);
void output_disable_LED_CHG_GREEN(void);

void enable_LED_INHIBIT(void);
void disable_LED_INHIBIT(void);
void output_enable_LED_INHIBIT(void);

#endif // USE_MACROS_FOR_IO

void enable_EN_KBD_PWR(void);
void disable_EN_KBD_PWR(void);
void output_enable_EN_KBD_PWR(void);
void output_disable_EN_KBD_PWR(void);

void pwm_io_init(void);
void sdi_io_init(void);

void pwm_init(void);
void leds_init(void);

void output_enable_LV_SET(void);
void output_disable_LV_SET(void);
void set_LV_SET(unsigned char value);

#endif
